package com.zhl.study.semaphore;

import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.util.concurrent.Semaphore;

/**
 * @description Semaphore是Java并发包中的一种计数信号量,它的作用是限制可以访问某些资源的线程数量。Semaphore可以控制同时访问特定资源的线程数量,从而限制资源并发访问的上限,保证了资源的互斥性。
 * Semaphore的常用方法:
 *      Semaphore(int permits)
 *          构造方法,创建一个具有给定的许可数和非公平的公平设置的Semaphore。
 *      Semaphore(int permits, boolean fair)
 *          构造方法,创建具有给定许可数和给定公平设置的Semaphore。
 *      void acquire() throws InterruptedException
 *          获取一个许可,在提供一个许可前一直将线程阻塞。
 *      void acquireUninterruptibly()
 *          获取一个许可,在提供一个许可之前将一直保持阻塞状态。
 *      boolean tryAcquire()
 *          尝试获取一个许可,如果可用则获取并立即返回true,否则立即返回false。
 *      boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
 *          尝试获取一个许可,如果在指定的等待时间内获取成功则返回true,否则返回false。
 *      void release()
 *          释放一个许可,将其返回到信号量。
 * @Author: z156940l@outlook.com
 * @className SemaphoreDemo
 * @Date: 2024/5/22 19:26
 */
@Slf4j
public class SemaphoreDemo {
    private final Semaphore TEN_SEMAPHORE = new Semaphore(10); // 最多10个连接
    private final Semaphore FIVE_SEMAPHORE = new Semaphore(5); // 最多5个线程并发
    private final Semaphore ONE_SEMAPHORE = new Semaphore(1); // 只允许一个线程写

    /**
     * 限制资源并发访问
     * 限制对某些资源的并发访问,例如数据库连接池、对象池等。示例代码:
     * @return
     */
    public Connection getConnection() {
        try {
            TEN_SEMAPHORE.acquire(); // 获取许可
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 从连接池获取连接
        return null;
    }

    public boolean releaseConnection(Connection conn) {
        TEN_SEMAPHORE.release(); // 释放许可
        // 将连接归还连接池
        return true;
    }

    /**
     * 控制线程并发数
     * 控制同时运行的线程数量,例如下载器、爬虫等。示例代码:
     * @param url
     */
    public void crawl(String url) {
        try {
            FIVE_SEMAPHORE.acquire(); // 获取许可
            // 下载并解析URL
            log.info("Crawling:{}", url);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            FIVE_SEMAPHORE.release(); // 释放许可
        }
    }

    /**
     * 实现读写锁
     * 使用一个Semaphore来限制对某个资源的并发写访问,允许多个线程同时读。示例代码:
     */
    public void writeData() {
        try {
            ONE_SEMAPHORE.acquire(); // 获取写锁
            // 写数据操作
            log.info("Writing data...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            ONE_SEMAPHORE.release(); // 释放写锁
        }
    }

    public void readData() {
        try {
            TEN_SEMAPHORE.acquire(); // 获取读锁
            // 读数据操作
            log.info("Reading data...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            TEN_SEMAPHORE.release(); // 释放读锁
        }
    }

    /**
     * 实现信号量(Semaphore)
     * Semaphore本身就是信号量的实现,可以用于多个线程之间的互斥和同步控制。示例代码:
     */
    public void doWork() {
        try {
            ONE_SEMAPHORE.acquire(); // 获取许可
            // 执行工作
            log.info("Working...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            ONE_SEMAPHORE.release(); // 释放许可
        }
    }
}
